#pragma once

#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include"inetaddr.hpp"
#include<cstring>

#include"log.hpp"


#define CONV(addr) (struct sockaddr*)(addr)
static const int g_backlog=8;

static const int g_sockfd=-1;

class Socket;

using SockPtr=std::shared_ptr<Socket>;

enum ExitCode{
    SOCKT_ERR=1,
};

class Socket //接口类
{
public:
    virtual ~Socket()=default;
    virtual int createSocket()=0; //创建socket
    virtual bool bindSocket(uint16_t port)=0;    //绑定socket
    virtual bool listenSocket()=0;        //监听socket
    virtual SockPtr accept(inetaddr* client)=0;        
    virtual void closeSocket()=0;         //关闭socket
    virtual size_t RecvData(std::string* out_string)=0; //向该socket发送信息
    virtual size_t SendData(std::string& in_string)=0;
    virtual int Fd()=0;

    void BulitTcpSocket(uint16_t port){
        bool r1=false,r2=false;
        while(!(r1||r2)){
            createSocket();
            r1=bindSocket(port);
            r2=listenSocket();
        }
    }
};

class TcpSocket :public Socket{
public:
    TcpSocket()=default;
    TcpSocket(int sockfd):_sockfd(sockfd){}
    ~TcpSocket(){
        closeSocket();
    };
    int createSocket() override{
        _sockfd=::socket(AF_INET,SOCK_STREAM,0);
        if(_sockfd<0){
            LOG(FATAL)<<"socket create fail";
            exit(SOCKT_ERR);
        }
        LOG(DEBUG)<<"socket create successful fd:"<<_sockfd;
        return _sockfd;
    }

    bool bindSocket(uint16_t port)override{
        inetaddr local(port);
        int n=::bind(_sockfd,CONV(local.sockaddr()),local.len());
        if(n==-1){
            LOG(ERROR)<<"bind fill:meeage[listenfd]:"<<_sockfd<<" [IP+port]:"<<local.addr();
            sleep(1);
            return false;
        }
        return true;
    }

    bool listenSocket()override{
        int n=::listen(_sockfd,g_backlog);
        if(n==-1){
            LOG(ERROR)<<"bind fill:meeage[listenfd]:"<<_sockfd;
            sleep(1);
            return false;
        }
        return true;
    };

    SockPtr accept(inetaddr* client)override{
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        int n=::accept(_sockfd,CONV(&peer),&len);
        if(n==-1){
            LOG(ERROR)<<"accept fail"<<strerror(errno);
            return nullptr;
        }
        client->setaddr(peer);

        return std::make_shared<TcpSocket>(n);
    }

    int Fd()override{return _sockfd;}

    size_t RecvData(std::string* out_string)override{
        char in_buffer[1024];
        int n=::recv(_sockfd,in_buffer,sizeof(in_buffer),0);
        if(n>0){
            in_buffer[n]=0;
            *out_string=in_buffer;
        }
        return n;
    }

    size_t SendData(std::string& in_string)override{
        int n=::send(_sockfd,in_string.c_str(),in_string.size(),0);
        return n;
    }

    void closeSocket(){
        if(_sockfd<0){  //如果文件描述符异常，那就不要关闭了，直接退出
            return;
        }
        ::close(_sockfd);
        _sockfd=g_sockfd;
    }
private:
    int _sockfd=g_sockfd;
};